﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Game.model;
using Game.utils;
using java.lang;
using java.util;
using lineage2.commons.net.nio.impl;
using lineage2.commons.time.cron;
using org.slf4j;
using String = java.lang.String;

namespace Game
{
    public class Shutdown:Thread
    {
        private static Logger _log = LoggerFactory.getLogger(typeof(Shutdown));
	    /**
	     * Field SHUTDOWN. (value is 0)
	     */
	    public const int SHUTDOWN = 0;
	    /**
	     * Field RESTART. (value is 2)
	     */
	    public const int RESTART = 2;
	    /**
	     * Field NONE. (value is -1)
	     */
	    public const int NONE = -1;
	    /**
	     * Field _instance.
	     */
	    private static Shutdown _instance = new Shutdown();
        public static Shutdown getInstance()
	    {
		    return _instance;
	    }
	
	    /**
	     * Field counter.
	     */
	    private Timer counter;
	    /**
	     * Field shutdownMode.
	     */
        static int shutdownMode;
	    /**
	     * Field shutdownCounter.
	     */
        static int shutdownCounter;
        private class ShutdownCounter:TimerTask
        {
            public ShutdownCounter()
		    {
			    // TODO Auto-generated constructor stub
		    }
		
		    /**
		     * Method run.
		     * @see java.lang.Runnable#run()
		     */
		    public override void run()
		    {
			    switch (shutdownCounter)
			    {
				    case 1800:
				    case 900:
				    case 600:
				    case 300:
				    case 240:
				    case 180:
				    case 120:
				    case 60:
					    Announcements.getInstance().announceByCustomMessage("THE_SERVER_WILL_BE_COMING_DOWN_IN_S1_MINUTES", new string[]
					    {
						    String.valueOf(shutdownCounter / 60)
					    });
					    break;
				    case 30:
				    case 20:
				    case 10:
				    case 5:
					    Announcements.getInstance().announceToAll(new SystemMessage(SystemMessage.THE_SERVER_WILL_BE_COMING_DOWN_IN_S1_SECONDS__PLEASE_FIND_A_SAFE_PLACE_TO_LOG_OUT).addNumber(shutdownCounter));
					    break;
				    case 0:
					    switch (shutdownMode)
					    {
						    case SHUTDOWN:
							    Runtime.getRuntime().exit(SHUTDOWN);
							    break;
						    case RESTART:
							    Runtime.getRuntime().exit(RESTART);
							    break;
					    }
					    cancel();
					    return;
			    }
			    shutdownCounter--;
		    }
        }
        private Shutdown()
        {
            setName(getClass().getSimpleName());
            setDaemon(true);
            shutdownMode = NONE;
        }
        public int getSeconds()
        {
            return shutdownMode == NONE ? -1 : shutdownCounter;
        }
        public int getMode()
        {
            return shutdownMode;
        }
        [MethodImpl(MethodImplOptions.Synchronized)]
        public void schedule(int seconds, int shutdownMode)
	    {
		    if (seconds < 0)
		    {
			    return;
		    }
		    if (counter != null)
		    {
			    counter.cancel();
		    }
		    Shutdown.shutdownMode = shutdownMode;
		    shutdownCounter = seconds;
		    _log.info("Scheduled server " + (shutdownMode == SHUTDOWN ? "shutdown" : "restart") + " in " + Util.formatTime(seconds) + ".");
		    counter = new Timer("ShutdownCounter", true);
		    counter.scheduleAtFixedRate(new ShutdownCounter(), 0, 1000L);
	    }
        public void schedule(System.String time, int shutdownMode)
        {
            SchedulingPattern cronTime;
            try
            {
                cronTime = new SchedulingPattern(time);
            }
            catch (SchedulingPattern.InvalidPatternException e)
            {
                return;
            }
            int seconds = (int)((cronTime.next(java.lang.System.currentTimeMillis()) / 1000L) - (java.lang.System.currentTimeMillis() / 1000L));
            schedule(seconds, shutdownMode);
        }
        [MethodImpl(MethodImplOptions.Synchronized)]
        public void cancel()
	    {
		    shutdownMode = NONE;
		    if (counter != null)
		    {
			    counter.cancel();
		    }
		    counter = null;
	    }
	    public override void run()
	    {
		    java.lang.System.@out.println("Shutting down LS/GS communication...");
		    LoginServerCommunication.getInstance().shutdown();
		    java.lang.System.@out.println("Shutting down scripts...");
		    Scripts.getInstance().shutdown();
		    java.lang.System.@out.println("Disconnecting players...");
		    disconnectAllPlayers();
		    java.lang.System.@out.println("Saving data...");
		    saveData();
		    try
		    {
			    java.lang.System.@out.println("Shutting down thread pool...");
			    ThreadPoolManager.getInstance().shutdown();
		    }
		    catch (java.lang.Exception e)
		    {
			    e.printStackTrace();
		    }
		    java.lang.System.@out.println("Shutting down selector...");
		    if (GameServer.getInstance() != null)
		    {
			    foreach (SelectorThread st in GameServer.getInstance().getSelectorThreads())
			    {
				    try
				    {
					    st.shutdown();
				    }
				    catch (java.lang.Exception e)
				    {
					    e.printStackTrace();
				    }
			    }
		    }
		    try
		    {
			    java.lang.System.@out.println("Shutting down database communication...");
			    DatabaseFactory.getInstance().shutdown();
		    }
		    catch (java.lang.Exception e)
		    {
			    e.printStackTrace();
		    }
		    java.lang.System.@out.println("Shutdown finished.");
	    }
        private void saveData()
	    {
		    if (Config.ENABLE_OLYMPIAD)
		    {
			    try
			    {
				    OlympiadDatabase.save();
				    java.lang.System.@out.println("Olympiad: Data saved.");
			    }
			    catch (java.lang.Exception e)
			    {
				    e.printStackTrace();
			    }
		    }
		    if (Config.ALLOW_WEDDING)
		    {
			    try
			    {
				    CoupleManager.getInstance().store();
				    java.lang.System.@out.println("CoupleManager: Data saved.");
			    }
			    catch (java.lang.Exception e)
			    {
				    e.printStackTrace();
			    }
		    }
		    try
		    {
			    FishingChampionShipManager.getInstance().shutdown();
			    java.lang.System.@out.println("FishingChampionShipManager: Data saved.");
		    }
		    catch (java.lang.Exception e)
		    {
			    e.printStackTrace();
		    }
		    try
		    {
			    Hero.getInstance().shutdown();
			    java.lang.System.@out.println("Hero: Data saved.");
		    }
		    catch (java.lang.Exception e)
		    {
			    e.printStackTrace();
		    }
		    if (Config.ALLOW_CURSED_WEAPONS)
		    {
			    try
			    {
				    CursedWeaponsManager.getInstance().saveData();
				    java.lang.System.@out.println("CursedWeaponsManager: Data saved,");
			    }
			    catch (java.lang.Exception e)
			    {
				    e.printStackTrace();
			    }
		    }
	    }
        private void disconnectAllPlayers()
	    {
		    foreach (Player player in GameObjectsStorage.getAllPlayersForIterate())
		    {
			    try
			    {
				    player.logout();
			    }
			    catch (java.lang.Exception e)
			    {
				    java.lang.System.@out.println("Error while disconnecting: " + player + "!");
				    e.printStackTrace();
			    }
		    }
	    }
    }
}
